'''
    1. 这里我主要写一下装饰器的作用，因为在abs模块中我采用到了,@装饰器
    2. 以下边列子，说明装饰器的使用
'''
'''
    1. 第一个列子，简单说明我们平常的函数。    
'''
# 平常我们实现一个输出,就是print打印就行了，如果想更改输出,在加输出就行了。
def func_foo():
    print("开始前的输出")
# 如果我们要更改输出在增加print就好了
    print("运行这个函数")
    print("结束后的输出")
# 运行
func_foo()

'''
    2. 第二个列子，简单说明我们平常多个函数改内容怎么办。
       是不是觉得很麻烦，我们这时候采用装饰器就ok了，可以节省掉，最下方的,func_foo2,3这两行代码。
       如何节省呢，我们@a_decorator就好了。运行效果一致。
'''
# 我们首先定义一个函数，然后等待往里传值。
def a_decorator(a_fuoo):
    def fuc_fo1():
        print("开始前的输出")
        # 因为我们这里传入的是一个函数，所以得是函数名()调用。
        a_fuoo()
        print("开始后的输出")
        # 我们返回这个函数的输出。
    return fuc_fo1()
@a_decorator
def func_fo2():
    print("运行fo2")
@a_decorator
def func_fo3():
    print("运行fo3")
# func_foo2=a_decorator(func_fo2)
# func_foo3=a_decorator(func_fo3)

'''
    1. 觉得上边那个列子，不太友好，自己想了一波，还是重构了一下。
    2. 第一个列子解释一下吧，我们是把函数func,赋予变量send_message，之后我们调用send_message，就是调用func
    3. 第二个例子，是一个把函数当参数传上去的。
    4. 第三个例子，是函数func_closure()的返回值是函数对象get_message()本身之后我们将其赋予变量send_message再调用send_message
'''
# 第一个列子。
def func(message):
    print("格式化:{}".format(message))
send_message=func
send_message("你好世界")
# 第二个例子
def get_message(message):
    return "你好"+message
def root_call(func,message):
    print(func(message))
res=root_call(get_message,"世界")
# 第三个例子
def func_closure():
    def get_message(message):
        print('你好: {}'.format(message))
    return get_message
send_message = func_closure()
send_message('世界')
# 第四个例子，和上边最早的第二个例子差不多。
'''
    1. 解释一下，@Func_send就是这样一句话,call_send=Func_send(call_send)
       本质意思就是，我们调用func_send这个函数，print输出，然后我们调用了message这个方法等于call_send，然后就会打印出call_send这个
       print输出的值。
'''
def Func_send(message):
    def func_send():
        print("猜猜我是不是第一个输出")
        message()
    return func_send
@Func_send
def call_send():
    print("你好世界")
call_send()
# 第五个例子，带有参数的装饰器
'''
    1. 解释一下，函数下方套了函数，传入了值,输出一句话，然后调用了最上方的函数,然后把值放在了里，然后返回了这个函数
        然后装饰器在waOne上，等于,waOne里的message(你好世界)传入给了func,func给了message
'''
def my_decorator(func):
    def wa(message):
        print("最早输出")
        func(message)
    return wa
@my_decorator
def waOne(mesagge):
    print("我要输出："+mesagge)
waOne("你好世界")
'''
    1. 如果有更多的参数，我们怎么办呢，用到*args,**kwargs，就能够解决问题了。
'''
def my_decoratorOne(func):
    def waa(*args,**kwargs):
        print("最早的")
        func(*args,**kwargs)
    return waa
@my_decoratorOne
def Aww(mess,message):
    print("哎！"+mess+message)
Aww("世界","你好")
'''
    1. 自定义的参数装饰器写法。
    2. 我们在最上方定义一个函数,有一个num值，在它的下下方函数all中被调用，然后循环遍历，循环结束后，执行func就是All这个函数。
'''
def repeat(num):
    def my_dec(func):
        def all(*args,**kwargs):
            for i in range(num):
                print("金金")
            func(*args,**kwargs)
        return all
    return my_dec
@repeat(4)
def All(message):
    print(message)
All("你好世界")
'''
    上方的讲解都是函数装饰器，下边写一下，类的装饰器。
    1. 类的装饰器这时候就依赖了一个魔术方法了__call__()
'''
class Count:
    def __init__(self,func):
        self.func=func
        self.num_class=0
    def __call__(self, *args, **kwargs):
        self.num_class+=1
        print("执行一次我们输出一次{}".format(self.num_class))
        return self.func(*args,**kwargs)
@Count
def example():
    print("输出example")
for i in range(3):
    example()

'''
    多个装饰器的例子，写法
'''
import functools
def my_dec1(func):
    @functools.wraps(func)
    def waa1(*args,**kwargs):
        print("第一次输出：1")
        func(*args,**kwargs)
    return waa1
def my_dec2(func):
    def waa2(*args,**kwargs):
        print("第二次输出：2")
        func(*args,**kwargs)
    return waa2
@my_dec1
@my_dec2
def qd(message):
    print(message+"不一样的")
qd("你好世界")